package com.fangzhi.service.impl;

import cn.hutool.db.Page;
import cn.hutool.db.sql.Order;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.BiIntFunction;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fangzhi.mapper.*;
import com.fangzhi.mobel.*;
import com.fangzhi.mobel.dto.OrderExcelDto;
import com.fangzhi.mobel.enums.GlobalCodeEnum;
import com.fangzhi.mobel.io.SaveOrderIo;
import com.fangzhi.mobel.vo.*;
import com.fangzhi.service.BadTypeService;
import com.fangzhi.service.CustomerService;
import com.fangzhi.service.OrdersService;
import com.fangzhi.service.ProductTypeService;
import com.fangzhi.utils.BeanCopyUtil;
import com.fangzhi.utils.GlobalParam;
import com.fangzhi.utils.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

/**
* @author edy
* @description 针对表【orders】的数据库操作Service实现
* @createDate 2024-09-18 14:12:43
*/
@Service
public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders>
    implements OrdersService{
    @Autowired
    private AdminAccountRoleDeptRelationMapper adminAccountRoleDeptRelationMapper;
    @Autowired
    private CustomerMapper customerMapper;
    @Autowired
    private OrderProductsMapper orderProductsMapper;
    @Autowired
    private ProductTypeService productTypeService;
    @Autowired
    private OrderPaymentMapper orderPaymentMapper;
    @Autowired
    private LogsMapper logsMapper;
    @Autowired
    private ProductTechnologyMapper productTechnologyMapper;
    @Autowired
    private BadTypeService badTypeService;
    @Autowired
    private OrderLogisticsMapper orderLogisticsMapper;
    @Autowired
    private OrderAfterMapper orderAfterMapper;
    @Autowired
    private OrderReceiptMapper orderReceiptMapper;

    @Override
    public Orders saveOrder(SaveOrderIo io) {
        LoginVo loginVo = GlobalParam.LOGIN_ACCOUNT_INFO.get();
        String orderId = createOrderId(io.getMaterialType());
        Orders orders = new Orders().setOrderId(orderId).setAdminAccountId(loginVo.getId())
                .setCustomer(io.getCustomerId()).setPriceType(io.getPriceType())
                .setMaterialType(io.getMaterialType()).setCustomerType(io.getCustomerType())
                .setStatus(3).setFreeShippingType(io.getFreeShippingType()).setComments(io.getComments());
        if(StringUtils.hasText(io.getImageComments())){
            orders.setImageComments(JSON.toJSONString(io.getImageComments().split(",")));
        }else{
            orders.setImageComments("[]");
        }


//        AdminAccountRoleDeptRelation adminAccountRoleDeptRelation = adminAccountRoleDeptRelationMapper.selectOne(Wrappers.<AdminAccountRoleDeptRelation>lambdaQuery()
//                .eq(AdminAccountRoleDeptRelation::getAdminAccounntId, loginVo.getId()));
//        if (adminAccountRoleDeptRelation.getRoleId() == 2)
//            orders.setStatus(2);

        boolean save = this.save(orders);
        if (save){
            logsMapper.insert(new Logs().setType(1).setType2(1).setAboutId(orders.getId()).setAdminAccountId(loginVo.getId()));
            return orders;
        }
        throw new RuntimeException("新增订单异常" + JSON.toJSONString(io));
    }


    @Override
    public ResponseResult orderList(String logisticsStr, String orderId, String name, Integer orderType, LocalDate beginTime, LocalDate endTime, List<Long> accountIds, Integer receiptType, Integer orderLogisticsType, Integer pageNo, Integer pageSize) {
        LoginVo loginVo = GlobalParam.LOGIN_ACCOUNT_INFO.get();
        AdminAccountRoleDeptRelation adminAccountRoleDeptRelation = adminAccountRoleDeptRelationMapper.selectOne(Wrappers
                .<AdminAccountRoleDeptRelation>lambdaQuery().eq(AdminAccountRoleDeptRelation::getAdminAccounntId, loginVo.getId()));
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String begin = null;
        String end = null;
        if (null != beginTime && null != endTime){
            begin = beginTime.format(dtf) + " 00:00:00";
            end = endTime.format(dtf) + " 23:59:59";
        }

        Long total = this.getBaseMapper().selectOrderListCount(logisticsStr, orderId, name, orderType, begin, end, accountIds, adminAccountRoleDeptRelation.getRoleId(), receiptType,  orderLogisticsType);
//        Long total = this.getBaseMapper().selectCount(Wrappers.<Orders>lambdaQuery()
//                .last(" left join customer c on c.id = customer")
//                .in(Orders::getAdminAccountId, accountIds)
//                .ge(null != begin, Orders::getCtime, begin)
//                .le(null != end, Orders::getCtime, end)
//                .in(adminAccountRoleDeptRelation.getRoleId() == 6, Orders::getStatus, Arrays.asList(2,3,4,5))
//                .last(" and c.name like %" + name + "%"));
        if (total == 0D)
            return ResponseResult.OK(new PageVo().setTotal(total).setData(new ArrayList<>()));

        List<OrderListVo> ordersList = this.getBaseMapper().selectOrderList(logisticsStr, orderId, name, orderType, begin, end, accountIds, adminAccountRoleDeptRelation.getRoleId(), receiptType,  orderLogisticsType, (pageNo - 1) * pageSize, pageSize);
        ordersList.forEach(T->{
            BigDecimal subtract = BigDecimal.valueOf(T.getTotalAmount())
                    .subtract(BigDecimal.valueOf(T.getDepositAmount()));
            T.setLogisticsPrice(subtract.doubleValue());
            // 计算订单回执总运费
            int receiptShippingFee = orderReceiptMapper.queryShippingFeeByOrderId(T.getOrderId());
            T.setReceiptShippingFee(receiptShippingFee / 100D);
        });
        return ResponseResult.OK(new PageVo().setTotal(total).setData(ordersList));
    }



    @Override
    public ResponseResult orderDetail(List<Long> accountIds, String orderId) {
        OrderDetailVo vo = this.getBaseMapper().queryOrderDetail(orderId, accountIds);
        if (null == vo)
            return ResponseResult.systemException(GlobalCodeEnum.GL_FAIL_9997);

        Orders one = this.getOne(Wrappers.<Orders>lambdaQuery().eq(Orders::getOrderId, orderId));
        List<String> strings = JSON.parseArray(one.getImageComments(), String.class);
        vo.setImageComments(strings);

        LoginVo loginVo = GlobalParam.LOGIN_ACCOUNT_INFO.get();
        AdminAccountRoleDeptRelation adminAccountRoleDeptRelation = adminAccountRoleDeptRelationMapper.selectOne(Wrappers.<AdminAccountRoleDeptRelation>lambdaQuery()
                .eq(AdminAccountRoleDeptRelation::getAdminAccounntId, loginVo.getId()));
        if (adminAccountRoleDeptRelation.getRoleId() == 2 && vo.getStatus() == 1){
            vo.setAdminStatus(1);
        }else if (adminAccountRoleDeptRelation.getRoleId() == 5 && vo.getStatus() == 2){
            vo.setAdminStatus(1);
        }

        List<OrderProducts> orderProducts = orderProductsMapper.selectList(Wrappers.<OrderProducts>lambdaQuery()
                .eq(OrderProducts::getOrderId, orderId));
        List<OrderDetailVo.Products> collect = orderProducts.stream().map(T -> {
            OrderDetailVo.Products products = new OrderDetailVo.Products();
            BadType badType = badTypeService.getById(T.getBadTypeId());
            List<Long> technologyIds = JSON.parseArray(T.getTechnologyId(), Long.class);
            int technologyPrice = 0;
            if (!technologyIds.isEmpty()){
                List<ProductTechnology> productTechnologies = productTechnologyMapper.selectList(Wrappers
                        .<ProductTechnology>lambdaQuery().in(ProductTechnology::getId, technologyIds));
                technologyPrice = productTechnologies.stream().mapToInt(ProductTechnology::getPrice).sum();
            }
            products.setTotalAmount(T.getTotalAmount() / 100D)
                    .setPriceCopy((T.getPrice() + technologyPrice) / 100D)
                    .setPriceCopy2(T.getPrice() / 100D)
                    .setNum(T.getNum()).setComments(T.getComments()).setProductName4(T.getThree())
                    .setProductName3(T.getTwo()).setProductName1(T.getOne()).setProductTypeId(T.getProductTypeId());
            List<Long> longs = JSON.parseArray(T.getTechnologyId(), Long.class);
            if (!longs.isEmpty()){
                List<OrderDetailVo.Products.Technoloyg> technoloygList = productTechnologyMapper.selectTechnogy(longs);
                products.setTechnologyList(technoloygList);
            }
            if (null != badType)
                products.setBadTypeId(badType.getId()).setBadTypeName(badType.getName());
            products.setTechnologyId(longs).setPrice((T.getPrice() + technologyPrice + T.getPremiumPrice()) / 100D).setPremiumPrice(T.getPremiumPrice() / 100D);
            return products;
        }).collect(Collectors.toList());
        vo.setProductList(collect);
        vo.setLogsVos(logsMapper.queryLogs(1, vo.getId()));
        List<OrderDetailVo.Payments> products =orderPaymentMapper.queryProductByOrderId(orderId);
        products.forEach(T->{
            if (adminAccountRoleDeptRelation.getRoleId() == 2 && T.getStatus() == 1){
                T.setAdminStatus(1);
            }else if (adminAccountRoleDeptRelation.getRoleId() == 5 && T.getStatus() == 2){
                T.setAdminStatus(1);
            }
            T.setLogsVos(logsMapper.queryLogs(2, T.getId()));
        });


        List<OrderDetailVo.Afters> aftersList = orderAfterMapper.queryAftersList(orderId);
        aftersList.forEach(T->{
            if (adminAccountRoleDeptRelation.getRoleId() == 2 && T.getStatus() == 1){
                T.setAdminStatus(1);
            }else if (adminAccountRoleDeptRelation.getRoleId() == 5 && T.getStatus() == 2){
                T.setAdminStatus(1);
            }
            T.setLogsVos(logsMapper.queryLogs(3, T.getId()));
        });
        vo.setPaymentsList(products).setAftersList(aftersList);
        BigDecimal subtract = BigDecimal.valueOf(vo.getTotalAmount()).subtract(BigDecimal.valueOf(vo.getDiscountAmount())).subtract(BigDecimal.valueOf(vo.getDepositAmount()));
        vo.setLogisticsPrice(subtract.doubleValue());
        List<QueryOrderLogisticsDetailVo.Detail> detailList = orderLogisticsMapper.queryOrderLogisticsDetail(orderId);
        vo.setDetailList(detailList);
        return ResponseResult.OK(vo);
    }

    @Override
    public ResponseResult unapprovedOrderList(List<Long> accountIds, Integer pageNo, Integer pageSize) {
        Long total = this.getBaseMapper().unapprovedOrderListCount(accountIds);
        if (total == 0L)
            return ResponseResult.OK(new PageVo().setTotal(total).setData(new ArrayList<>()));

        List<OrderListVo> list = this.getBaseMapper().unapprovedOrderList(accountIds, (pageNo - 1) * pageSize, pageSize);
        list.forEach(T->{
            BigDecimal subtract = BigDecimal.valueOf(T.getTotalAmount()).subtract(BigDecimal.valueOf(T.getDiscountAmount())).subtract(BigDecimal.valueOf(T.getDepositAmount()));
            T.setLogisticsPrice(subtract.doubleValue());
        });
        return ResponseResult.OK(new PageVo().setTotal(total).setData(list));
    }

    @Override
    public ResponseResult unapprovedOrderListFour(Integer pageNo, Integer pageSize) {
        Long total = this.getBaseMapper().selectCount(Wrappers.<Orders>lambdaQuery().
                eq(Orders::getStatus, 3).isNull(Orders::getLogisticId).isNull(Orders::getLogisticName));
        if (total == 0L)
            return ResponseResult.OK(new PageVo().setTotal(total).setData(new ArrayList<>()));

        List<OrderListVo> list = this.getBaseMapper().unapprovedOrderListFour((pageNo - 1) * pageSize, pageSize);
        list.forEach(T->{
            BigDecimal subtract = BigDecimal.valueOf(T.getTotalAmount()).subtract(BigDecimal.valueOf(T.getDepositAmount()));
            T.setLogisticsPrice(subtract.doubleValue());
        });
        return ResponseResult.OK(new PageVo().setTotal(total).setData(list));
    }

    @Override
    public ResponseResult unapprovedOrderListFive(Integer pageNo, Integer pageSize) {
        Long total = this.getBaseMapper().unapprovedOrderListFiveCount();
        if (total == 0L)
            return ResponseResult.OK(new PageVo().setTotal(total).setData(new ArrayList<>()));

        List<OrderListVo> list = this.getBaseMapper().unapprovedOrderListFive((pageNo - 1) * pageSize, pageSize);
        list.forEach(T->{
            BigDecimal subtract = BigDecimal.valueOf(T.getTotalAmount()).subtract(BigDecimal.valueOf(T.getDiscountAmount())).subtract(BigDecimal.valueOf(T.getDepositAmount()));
            T.setLogisticsPrice(subtract.doubleValue());
        });
        return ResponseResult.OK(new PageVo().setTotal(total).setData(list));
    }


    @Override
    public ResponseResult toExists(Integer id, Integer needStatus, Integer pass) {
        Orders orders = this.getBaseMapper().selectById(id);
        if (orders.getStatus() != needStatus)
            return ResponseResult.systemException(GlobalCodeEnum.GL_FAIL_9996);
        if (pass == 1){
            orders.setStatus(needStatus + 1);
        } else if (pass == 2) {
            orders.setStatus(6);
        }
        LoginVo loginVo = GlobalParam.LOGIN_ACCOUNT_INFO.get();
        AdminAccountRoleDeptRelation adminAccountRoleDeptRelation = adminAccountRoleDeptRelationMapper.selectOne(Wrappers.<AdminAccountRoleDeptRelation>lambdaQuery()
                .eq(AdminAccountRoleDeptRelation::getAdminAccounntId, loginVo.getId()));
        OrderPayment orderPayment = orderPaymentMapper.selectOne(Wrappers.<OrderPayment>lambdaQuery().eq(OrderPayment::getType, 1).eq(OrderPayment::getOrderId, orders.getOrderId()));
        if (null != orderPayment && adminAccountRoleDeptRelation.getRoleId() ==  5){
            // 财务审核
            Logs logs = new Logs().setType(2).setType2(2).setAboutId(orderPayment.getId())
                    .setAdminAccountId(orders.getAdminAccountId());
            if (pass == 1){
                logs.setType3(1);
            }else if (pass == 2){
                logs.setType3(2);
            }
            orderPayment.setStatus(3);
            orderPaymentMapper.updateById(orderPayment);
            logsMapper.insert(logs);
        }else if(null != orderPayment && adminAccountRoleDeptRelation.getRoleId() == 2){
            Logs logs = new Logs().setType(2).setType2(2).setAboutId(orderPayment.getId())
                    .setAdminAccountId(orders.getAdminAccountId());
            if (pass == 1){
                logs.setType3(1);
            }else if (pass == 2){
                logs.setType3(2);
            }
            orderPayment.setStatus(2);
            orderPaymentMapper.updateById(orderPayment);
            logsMapper.insert(logs);
        }

        int i = this.getBaseMapper().updateById(orders);
        if (i == 1){
            Logs logs = new Logs().setType(1).setType2(2).setAboutId(orders.getId())
                    .setAdminAccountId(orders.getAdminAccountId()).setType3(1);
            if (pass == 2)
                logs.setType3(2);
            logsMapper.insert(logs);
            return ResponseResult.OK();
        }
        throw new RuntimeException("审核订单状态");
    }

    @Override
    public ResponseResult orderCount(YearMonth time) {
        LocalDate start = time.atDay(1);
        LocalDate end = start.withDayOfMonth(start.lengthOfMonth());
        long count = this.count(Wrappers.<Orders>lambdaQuery().between(Orders::getCtime, start, end).in(Orders::getStatus, Arrays.asList(3, 4, 5)));
        long allCount = this.count(Wrappers.<Orders>lambdaQuery().in(Orders::getStatus, Arrays.asList(3, 4, 5)));
        return ResponseResult.OK(new OrderCountVo().setCount(count).setAllCount(allCount));
    }

    @Override
    public ResponseResult salesPrice(YearMonth time) {
        LocalDate start = time.atDay(1);
        LocalDate end = start.withDayOfMonth(start.lengthOfMonth());
        List<Orders> list = this.list(Wrappers.<Orders>lambdaQuery().between(Orders::getCtime, start, end).in(Orders::getStatus, Arrays.asList(3, 4, 5)));
        List<Orders> allList = this.list(Wrappers.<Orders>lambdaQuery().in(Orders::getStatus, Arrays.asList(3, 4, 5)));
        int price = list.stream().mapToInt(T -> T.getTotalAmount() - T.getDiscountAmount()).sum();
        int allPrice = allList.stream().mapToInt(T -> T.getTotalAmount() - T.getDiscountAmount()).sum();
        return ResponseResult.OK(new SalesPriceVo().setPrice(price / 100D).setAllPrice(allPrice / 100D));
    }

    @Override
    public List<OrderExcelDto> queryOrderExcelList(String orderId, String name, LocalDate beginTime, LocalDate endTime, List<Long> accountIds, Integer userId) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String begin = null;
        String end = null;
        if (null != beginTime && null != endTime){
            begin = beginTime.format(dtf) + " 00:00:00";
            end = endTime.format(dtf) + " 23:59:59";
        }
        List<OrderExcelDto> excelDtoList = this.getBaseMapper().queryOrderExcelList(orderId, name, begin, end, accountIds, userId);
        return excelDtoList;
    }

    @Override
    public QueryOrderLogisticsDetailVo queryOrderLogistics(String orderId) {
        return this.getBaseMapper().queryOrderLogistics(orderId);
    }

    @Override
    public ResponseResult queryOrderByHotelName(String hotelName) {
        List<QueryOrderByHotelNameVo> voList = this.getBaseMapper().queryOrderByHotelName(hotelName);
        return ResponseResult.OK(voList);
    }

    @Override
    public Orders updateOrder(String orderId, SaveOrderIo io) {
        Orders orders = this.getBaseMapper().selectOne(Wrappers.<Orders>lambdaQuery().eq(Orders::getOrderId, orderId));
        orders.setStatus(3).setMaterialType(io.getMaterialType()).setCustomer(io.getCustomerId())
                .setPriceType(io.getPriceType()).setCustomerType(io.getCustomerType())
                .setFreeShippingType(io.getFreeShippingType()).setComments(io.getComments());
        if(StringUtils.hasText(io.getImageComments())){
            orders.setImageComments(JSON.toJSONString(io.getImageComments().split(",")));
        }else{
            orders.setImageComments("[]");
        }
        if (io.getMaterialType() == 1){
            orders.setOrderId(orders.getOrderId().replace("B", "H"));
        }else if (io.getMaterialType() == 2){
            orders.setOrderId(orders.getOrderId().replace("H", "B"));
        }
        this.getBaseMapper().updateById(orders);
        return orders;
    }


    public String createOrderId(Integer type){
        StringBuilder sb = new StringBuilder();
        if (type == 1){
            sb.append("H");
        }else if (type == 2){
            sb.append("B");
        }
        sb.append(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        Random rand = new Random();
        for (int i = 0; i < 5; i++) {
            sb.append(rand.nextInt(10));
        }
        Long total = this.getBaseMapper().selectCount(Wrappers.<Orders>lambdaQuery().eq(Orders::getOrderId, sb.toString()));
        if (total == 0L)
            return sb.toString();
        return createOrderId(type);
    }

}




